package com.powergisol.gis.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.enums.WriteDirectionEnum;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.powergisol.gis.Enum.ServiceTypeEnum;
import com.powergisol.gis.dao.TabDataSettingMapper;
import com.powergisol.gis.dao.TabMouldMapper;
import com.powergisol.gis.dao.TabPipeMapper;
import com.powergisol.gis.dao.TabTaskMapper;
import com.powergisol.gis.entity.*;
import com.powergisol.gis.exception.GlobalExceptionHandler;
import com.powergisol.gis.listener.PipeExcelModelListener;
import com.powergisol.gis.service.TabPipeService;
import com.powergisol.gis.util.Result;
import com.powergisol.gis.util.ZipUtils;
import com.powergisol.gis.vo.*;
import org.apache.commons.io.FileUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class TabPipeServiceImpl implements TabPipeService {
    @Value("${earth-url}")
    private String earthUrl;
    @Value("${file.excel-path}")
    private String excelPath;
    @Autowired
    TabPipeMapper tabPipeMapper;

    @Autowired
    private TabMouldMapper tabMouldMapper;

    @Autowired
    private TabDataSettingMapper tabDataSettingMapper;

    @Autowired
    private TabTaskMapper tabTaskMapper;

    @Autowired
    private TabDataSettingMapper settingMapper;

    @Autowired
    private  CacheManager cacheManager;

    @Autowired
    TabPipeStaticColorServiceImpl colorService;

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = {Exception.class})
    @Override
    public Result importFile(MultipartFile file, WangXianVO vo, TabUserVo tabUserVo ) {
        String fuwuname = file.getOriginalFilename().substring(0, file.getOriginalFilename().indexOf("."));
        //文件后缀
        String suffixName = file.getOriginalFilename().substring(file.getOriginalFilename().indexOf("."));
        //服务注册
        Map<String, Integer> map = saveService(fuwuname, suffixName, vo, tabUserVo);
        int tabTaskId = map.get("tabTaskId");
        int settingId = map.get("dataSettingId");
        ExcelReader excelReader = null;
        TabCoordinateSystem system = new TabCoordinateSystem();
        if ("1".equals(vo.getIsChange())) {
            system = tabMouldMapper.getCoorByName(vo.getCoorName());
        }
        Cache cache = cacheManager.getCache("cache-data");
        try {
            excelReader = EasyExcel.read(file.getInputStream()).build();
            List<Sheet> sheets = excelReader.getSheets();
            for (int i = 0; i < sheets.size(); i++) {
                ReadSheet readSheet = EasyExcel.readSheet(i).head(TabPipeVO.class).registerReadListener(new PipeExcelModelListener(settingId, vo, system, tabPipeMapper)).headRowNumber(1).build();
                double result = (Double.valueOf(readSheet.getSheetNo() + 1) / Double.valueOf(sheets.size())) * 100;
                cache.put(vo.getUuid() + "progress", result);
                if (result == 100.0) {
                    TabTask tabTask = new TabTask();
                    tabTask.setTaskState(1);
                    tabTask.setProgress(100.0);
                    tabTask.setId(tabTaskId);
                    tabTaskMapper.upTabTask(tabTask);
                }
                excelReader.read(readSheet);
            }
            List<TabPipeStaticColor> colorList = new ArrayList<>();
            List<String> allClass = getAllClass(vo.getUuid());
            allClass.forEach(x->{
                TabPipeStaticColor color = new TabPipeStaticColor();
                color.setWgType(x);
                color.setDistinguish("1");
                colorList.add(color);
            });
            List<String> materialClass = getMaterialClass(vo.getUuid());
            materialClass.forEach(m->{
                TabPipeStaticColor color = new TabPipeStaticColor();
                color.setWgType(m);
                color.setDistinguish("2");
                colorList.add(color);
            });
            PipeStaticColorVO staticColorVO = new PipeStaticColorVO();
            staticColorVO.setUuid(vo.getUuid());
            staticColorVO.setColors(colorList);
            colorService.insertBatch(staticColorVO);
        } catch (Exception e) {
            TabTask tabTask = new TabTask();
            tabTask.setId(tabTaskId);
            tabTask.setTaskState(2);
            tabTask.setRemark("管网导入失败:数据解析错误");
            tabTaskMapper.upTabTask(tabTask);
            e.printStackTrace();
            throw new GlobalExceptionHandler(400, "数据解析失败");
        } finally {
            if (excelReader != null) {
                // 这里千万别忘记关闭，读的时候会创建临时文件，到时磁盘会崩的
                excelReader.finish();
            }
        }
        return new Result().success("文件导入成功");
    }


    private Map<String, Integer> saveService(String fileName, String suffixName, WangXianVO vo, TabUserVo tabUserVo) throws RuntimeException {
        String uuid = vo.getUuid();
        String userDir = System.getProperty("user.dir");
        userDir = userDir.substring(0, userDir.lastIndexOf(File.separator)) + File.separator + "Upload" + File.separator + "excel" + File.separator + uuid + suffixName;
        //发布服务
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMddHHmmss");
        String serviceName = fileName + sdf1.format(new Date());
        TabServiceVo tabServiceVo = new TabServiceVo();
        tabServiceVo.setServiceUrl(earthUrl + serviceName);
        //根据用户查询用户
        tabServiceVo.setUserId(tabUserVo.getId());
        tabServiceVo.setState(1);
        tabServiceVo.setName(serviceName);
        tabServiceVo.setReleaseTime(new Date());
        tabServiceVo.setServiceType(ServiceTypeEnum.GWEXCEL.getValue());
        tabServiceVo.setUuid(vo.getUuid());

        tabDataSettingMapper.saveService(tabServiceVo);
        tabDataSettingMapper.saveUserService(tabServiceVo.getUserId(), tabServiceVo.getId());
        int serviceId = tabServiceVo.getId();
        TabDataSetting dataSetting = new TabDataSetting();
        dataSetting.setUuid(vo.getUuid());
        dataSetting.setCreateUser(tabUserVo.getName());
        dataSetting.setDataType(1);
        dataSetting.setDataUrl(userDir);
        dataSetting.setCreateTime(new Date());
        dataSetting.setServiceId(serviceId);
        dataSetting.setCoorName(vo.getCoorName());
        //保存入库
        tabDataSettingMapper.saveDataSetting(dataSetting);
        TabTask tabTask = new TabTask();
        tabTask.setUserId(tabUserVo.getId());
        tabTask.setUuid(vo.getUuid());
        tabTask.setTaskName(serviceName);
        tabTask.setTaskTime(new Date());
        tabTask.setTaskType(2);
        tabTask.setTaskState(0);
        tabTask.setProgress(0d);
        tabTask.setServiceId(tabServiceVo.getId());
        tabTask.setServiceType(10);
        tabTask.setServiceName(serviceName);
        tabTask.setServiceUrl(earthUrl+serviceName);
        tabTaskMapper.saveTabTask(tabTask);
        Map<String, Integer> map = new HashMap<>();
        map.put("tabTaskId", tabTask.getId());
        int dataSettingId = dataSetting.getId();
        map.put("dataSettingId", dataSettingId);
        return map;
    }

    /**
     * 数据导出
     *
     * @param exportPipeVo 参数
     * @param response     响应
     */
    @Override
    public void exportFile(ExportPipeVo exportPipeVo, HttpServletResponse response) throws RuntimeException {
        //拿到所有的管线类型
        List<String> wgTypes = tabPipeMapper.getClassBySetId(exportPipeVo.getSettingId());
        //根据settingId和用户传的管线类型查询需要导出的数据
        List<TabPipe> pipeList = tabPipeMapper.selectAll(exportPipeVo.getSettingId(), exportPipeVo.getWgTypes());
        if (pipeList.isEmpty() && pipeList.size() <= 0) {
            new GlobalExceptionHandler( "该管线数据不存在");
        }
        //获取模板
        Resource resource = new ClassPathResource("template/wgtemplate.xlsx");
        //导出的文件路径
        String fileName = excelPath + File.separator + UUID.randomUUID().toString().replaceAll("-", "") + ".xlsx";
        InputStream tempInput = null;
        File tempFile = null;
        Workbook wb = null;
        try {
            //复制一个临时文件
            tempInput = resource.getInputStream();
            tempFile = new File(excelPath + File.separator + System.currentTimeMillis() + ".xlsx");
            if (!tempFile.getParentFile().exists()) {
                tempFile.getParentFile().mkdirs();
            }
            FileOutputStream fileOutputStream = new FileOutputStream(tempFile);
            //将流写入到这个临时文件中
            FileUtils.copyInputStreamToFile(tempInput, tempFile);

            wb = new XSSFWorkbook(tempFile);
            //如果用户传了需要导出的管线类型，就根据这些类型进行创建sheet
            if (exportPipeVo.getWgTypes() != null && !exportPipeVo.getWgTypes().isEmpty() && exportPipeVo.getWgTypes().size() > 0) {
                for (int i = 0; i < exportPipeVo.getWgTypes().size(); i++) {
                    wb.cloneSheet(0);
                    wb.setSheetName(i, exportPipeVo.getWgTypes().get(i));
                }
                wb.removeSheetAt(exportPipeVo.getWgTypes().size());
            } else {//如果没有传，就是导出这个settingId下的所有类型
                for (int i = 0; i < wgTypes.size(); i++) {
                    wb.cloneSheet(0);
                    wb.setSheetName(i, wgTypes.get(i));
                }
                wb.removeSheetAt(wgTypes.size());
            }
            wb.write(fileOutputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (wb != null) {
                    wb.close();
                }
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        }
        //生成导出文件
        File file = new File(fileName);

        ExcelWriter excelWriter = null;
        try {
            //将被写入文件，以及临时的模板文件放入EasyExcel中
            excelWriter = EasyExcel.write(fileName).withTemplate(tempFile).build();
        } catch (Exception e) {
            e.printStackTrace();
        }
        for (String wgType : wgTypes) {
            //根据类型集合 在查询出来的数据中筛选出对应的管线
            List<TabPipe> tabPipeList = pipeList.stream().filter(x -> x.getPipeLx().equals(wgType)).collect(Collectors.toList());
            tabPipeList.sort(Comparator.comparing(TabPipe::getPipePreno));
            if (tabPipeList.size() > 0 && !tabPipeList.isEmpty()) {
                //写入到对应的Sheet中
                WriteSheet writerSheet = EasyExcel.writerSheet(wgType).build();

                FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.VERTICAL).build();

                excelWriter.fill(tabPipeList, fillConfig, writerSheet);

                Map<String, Object> map = new HashMap<>();

                map.put("pipeZone", tabPipeList.get(0).getPipeZone());

                map.put("pipeLx", tabPipeList.get(0).getPipeLx());

                map.put("pipeDrawNo", tabPipeList.get(0).getPipeDrawNo());

                map.put("pipeCompany", tabPipeList.get(0).getPipeCompany());

                map.put("checkDate", tabPipeList.get(0).getCheckDate());

                excelWriter.fill(map, writerSheet);

            }
        }
        //关闭流
        excelWriter.finish();
        //删除临时模板文件
        FileUtils.deleteQuietly(tempFile);
        //文件导出
        ZipUtils.estampDown(file, response);
    }

    /**
     * 管线详情
     * @param pipeDetailsVO
     * @return
     */
    @Override
    public Map<String, List<TabPipe>> selectDetails(PipeDetailsVO pipeDetailsVO) {
        long l = System.currentTimeMillis();
        Integer serviceId = pipeDetailsVO.getServiceId();
        TabDataSetting byServiceId = tabDataSettingMapper.getByServiceId(serviceId);
        pipeDetailsVO.setSettingId(byServiceId.getId());
        List<TabPipe> pipeList = tabPipeMapper.selectDetails(pipeDetailsVO);
        System.out.println("过滤前："+pipeList.size());
        if(pipeDetailsVO.getPipePrenos()!=null && pipeDetailsVO.getPipePrenos().size()>0){
            List<TabPipe> resultList = pipeList.stream().filter(x -> pipeDetailsVO.getPipePrenos().contains(x.getPipePreno())).collect(Collectors.toList());
            System.out.println("过滤后："+resultList.size());
            Map<String, List<TabPipe>> pipeMap = resultList.stream().collect(Collectors.groupingBy(TabPipe::getPipePreno));
            System.out.println("管网详情查询耗时:"+(System.currentTimeMillis()-l));
            return pipeMap;
        }
        //根据预编号进行分组
        Map<String, List<TabPipe>> pipeMap = pipeList.stream().collect(Collectors.groupingBy(TabPipe::getPipePreno));
        System.out.println("管网详情查询耗时:"+(System.currentTimeMillis()-l));
        return pipeMap;
    }

    /**
     * 查询管线类型
     * @param uuid
     * @return
     */
    @Override
    public List<String> getAllClass(String uuid) {
        TabDataSetting one =settingMapper.getOneByUuid(uuid);
        List<String> pipeType = tabPipeMapper.getAllClass(one.getId());
        return pipeType;
    }

    /**
     * 查询材料类型
     * @param uuid
     * @return
     */
    @Override
    public List<String> getMaterialClass(String uuid) {
        TabDataSetting one =settingMapper.getOneByUuid(uuid);
        List<String> materialType = tabPipeMapper.getMaterialClass(one.getId());
        return materialType;
    }
}
